home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / util / misc / Fudgit233.lha / Source / src / dl / dl_ldzfilep.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-14  |  7.1 KB  |  229 lines

  1. /***********************************************************
  2. Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The
  3. Netherlands.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Stichting Mathematisch
  12. Centrum or CWI not be used in advertising or publicity pertaining to
  13. distribution of the software without specific, written prior permission.
  14.  
  15. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16. THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  18. FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  21. OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  
  23. ******************************************************************/
  24. /*
  25. ** dl_ldzfilep - Load ZMAGIC file using mmap
  26. */
  27.  
  28. #define _auxtemp _auxtemp1    /* A bug in ldfcn.h */
  29.  
  30. #include <stdio.h>
  31. #include <filehdr.h>
  32. #include <syms.h>
  33. #include <ar.h>
  34. #include <scnhdr.h>
  35. #include <ldfcn.h>
  36. #include <nlist.h>
  37. #include <assert.h>
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <sys/fcntl.h>
  41. #include <sys/mman.h>
  42.  
  43. #include "dl.h"
  44.  
  45. #ifdef DEBUG
  46. #define D(x) (x)
  47. #else
  48. #define D(x)
  49. #endif /* DEBUG */
  50.  
  51. /*
  52. ** dl_ldzfilep loads a ZMAGIC file into memory using mmap() calls (thereby
  53. ** making at least the text segment of the binary demand-paged form the
  54. ** original load image).
  55. **
  56. ** Due to some ideosyncracies in the way mmap() work we have to collect all
  57. ** BSS and DATA segments and map them together. The current code only works
  58. ** well if the following two things are true:
  59. ** - All data segments (rdata, data, sdata, etc) are contiguous, and the
  60. **   sections in the load file are sorted on address and their data is
  61. **   stored contiguous
  62. ** - All bss segment section descriptors are contiguous, their sections are
  63. **   sorted on address and they follow all the data segments.
  64. **
  65. ** As far as I can tell this is true for all normal binaries.
  66. ** Unexpected things may happen if this is untrue, since the routine does
  67. ** only some very cursory checks to verify these hypotheses.
  68. */
  69.  
  70. extern int getpagesize (void);
  71. extern int open (const char *, int, ...);
  72. extern int close (int);
  73. extern off_t lseek (int, off_t, int);
  74. extern int read (int, void *, unsigned int);
  75.  
  76. int
  77. dl_ldzfilep(struct ldfile *ldptr, char *fn)
  78. {
  79.     int i;
  80.     int nsect;                /* Number of sections */
  81.     struct scnhdr shdr;            /* Current section header */
  82.     int fd;                /* load file fd (for mmap) */
  83.     int nullfd;                /* /dev/zero fd (for bss mmap) */
  84.     unsigned long addr, eaddr, off;    /* rounded section address/file-off */
  85.     unsigned long pagesize, pagemask;    /* mmu parameters */
  86.     void *rv;                /* mmap return value */
  87.     unsigned long lodata, hidata, lobss, hibss;    /* Data/bss location */
  88.     unsigned long offdata;
  89.     int hasdata, hasbss;
  90.  
  91.     /*
  92.     ** First some initializations.
  93.     */
  94.     pagesize = getpagesize();
  95.     pagemask = pagesize-1;
  96.     assert ( (pagesize|pagemask) == pagesize+pagemask);
  97.     fd = open(fn,O_RDONLY);
  98.     if(fd < 0) {
  99.     dl_error("Could not open fd for mmap on %s", fn);
  100.     return 0;
  101.     }
  102.     if ( (nullfd = open("/dev/zero", 0)) < 0) {
  103.     dl_error(0, "/dev/zero");
  104.     close(fd);
  105.         return 0;
  106.     }
  107.     nsect = HEADER(ldptr).f_nscns;
  108.     D(printf("loadfile: %d sections\n", nsect));
  109.     D(printf("loadfile: version stamp=%d, 0x%x\n", SYMHEADER(ldptr).vstamp,
  110.          SYMHEADER(ldptr).vstamp));
  111.     /*
  112.     ** Now loop over the sections, and load them if needed.
  113.     */
  114.     lodata = lobss = 0xffffffff;
  115.     hidata = hibss = 0;
  116.     hasdata = hasbss = 0;
  117.     offdata = 0xffffffff;
  118.     for ( i=1; i<nsect+1; i++ ) {
  119.     if ( ldshread(ldptr, i, &shdr) == FAILURE ) {
  120.         dl_error("Cannot read section header %d", (char *)i);
  121.         close(nullfd); close(fd);
  122.         return 0;
  123.     }
  124.     D(printf("loadfile: section %d=%s, 0x%x:0x%x@0x%x type 0x%x\n", i,
  125.            shdr.s_name, shdr.s_vaddr, shdr.s_size, shdr.s_scnptr, shdr.s_flags));
  126.     if ( shdr.s_scnptr &&
  127.                     (shdr.s_vaddr&pagemask) != (shdr.s_scnptr&pagemask) ) {
  128.         /* Incorrectly aligned segment */
  129.         dl_error("Incorrect alignment in section %d", (char *)i);
  130.         close(nullfd); close(fd);
  131.         return 0;
  132.     }
  133.     addr = shdr.s_vaddr & ~pagemask;
  134.     eaddr = shdr.s_vaddr + shdr.s_size;
  135.     off = shdr.s_scnptr & ~pagemask;
  136.     D(printf("Addr %x, off %x\n", addr, off));
  137.     /*
  138.     ** We would like to use the lower 4 bits in s_flags here to decide
  139.     ** what to do with the segment (allocate/load), but they don't seem
  140.     ** to be set correctly. So, we have to fiddle.
  141.     */
  142.     switch(shdr.s_flags) {
  143.     case STYP_TEXT:
  144.         if ( !dl_setrange(addr, eaddr) )
  145.           return 0;
  146.         rv = mmap((void *)addr, eaddr - addr, PROT_READ|PROT_EXECUTE,
  147.             MAP_SHARED|MAP_FIXED, fd, off);
  148.         D(printf("rv=%x addr=%x\n", rv, addr));
  149.         if ( addr != (unsigned long)rv ) {
  150.         dl_error(0, "mmap(.text)");
  151.         close(nullfd); close(fd);
  152.             return 0;
  153.         }
  154.         break;
  155.     case STYP_DATA:
  156.     case STYP_RDATA:
  157.     case STYP_SDATA:
  158.     case STYP_LIT8:
  159.     case STYP_LIT4:
  160.         /* Could do many more sanity checks here */
  161.         if ( addr < lodata) {
  162.         if ( lodata != 0xffffffff ) {
  163.             dl_error("Data segments incorrectly ordered", 0);
  164.             close(nullfd); close(fd);
  165.             return 0;
  166.         }
  167.         lodata = addr;
  168.         }
  169.         if ( eaddr > hidata )
  170.           hidata = eaddr;
  171.         if ( off < offdata )
  172.           offdata = off;
  173.         hasdata = 1;
  174.         break;
  175.     case STYP_BSS:
  176.     case STYP_SBSS:
  177.         if ( addr < lobss )
  178.           lobss = addr;
  179.         if ( eaddr > hibss )
  180.           hibss = eaddr;
  181.         hasbss = 1;
  182.         break;
  183.     case _STYP_RESOURCE:
  184.         break;
  185.     default:
  186.         dl_error("Unknown section type 0x%x", (char *)shdr.s_flags);
  187.         close(nullfd); close(fd);
  188.         return 0;
  189.     }
  190.     }
  191.     /*
  192.     ** Now map in all of data space, if there is any.
  193.     ** It seems we can't map bss space into the same region, so
  194.     ** we map all of it private, and read it in ourselves.
  195.     */
  196.     if ( hasdata || hasbss ) {
  197.     if ( hasdata && hasbss && hibss < hidata ) {
  198.         /* Segments in the wrong order */
  199.         dl_error(0, "data/bss segments in wrong order");
  200.         return 0;
  201.     }
  202.     if ( !hasdata )
  203.       lodata = hidata = lobss;
  204.     if ( !hasbss )
  205.       lobss = hibss = hidata;
  206.     D(printf("Data mmap(0x%x, 0x%x, ...)\n", lodata, hibss-lodata));
  207.     if( !dl_setrange(lodata, hibss) )
  208.       return 0;
  209.     rv = mmap((void *)lodata, hibss-lodata, PROT_READ|PROT_WRITE,
  210.           MAP_PRIVATE|MAP_FIXED, nullfd, 0);
  211.     if ( (unsigned long)rv != lodata ) {
  212.         D(printf("mmap(data)=0x%x, not 0x%x\n", rv, lodata));
  213.         dl_error(0, "mmap(data segments)");
  214.         close(nullfd); close(fd);
  215.         return 0;
  216.     }
  217.     if ( hasdata ) {
  218.         D(printf("Data read 0x%x..0x%x from 0x%x\n", lodata, hidata, offdata));
  219.         lseek(fd, offdata, 0);
  220.         if ( read(fd, (void *)lodata, hidata-lodata) != hidata-lodata ) {
  221.         dl_error(0, "Could not read data segments");
  222.         return 0;
  223.         }
  224.     }
  225.     }
  226.     close(nullfd);
  227.     return 1;
  228. }
  229.